/*******************************************************************************
 * Copyright 2009-2013 Andy Shaules
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.thebitstream.comserver.feeds;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.red5.io.utils.ObjectMap;
import org.red5.server.net.rtmp.event.Notify;
import org.red5.server.net.rtmp.event.VideoData;

import com.thebitstream.comserver.feeds.SimpleFeedBase;
import com.thebitstream.comserver.nodes.IComserverNode;
import com.thebitstream.comserver.stream.IResourceSink;
import com.thebitstream.comserver.stream.util.InvocationFactory;


/**
 * Node data broadcaster. 
 * <p>Every resource stores a reference to all the Nodes that are currently subscribed.
 * The RoomTicker gets the list of nodes and broadcasts the node data.
 * It uses the periodic tick thread generated by the resource executor. 
 * Each Resource sink provides a 'courtesy tick' to the feeds. 
 * A more advanced feed should create it's own thread and ignore the ticker 'execute' method. 
 * The resource ticker interval is set in the Application super class and is used for all resources. Default is one tick per second.</p>
 * 
 * @author Andy Shaules
 * @version 1.0
 */
public class RoomTicker extends SimpleFeedBase{
	
	ArrayList<Object>joined=new ArrayList<Object>();
	
	ArrayList<Object>parted=new ArrayList<Object>();

	//This is a shared thread. 
	//If you need your own dedicated thread, create one.
	@Override
	public void execute(IResourceSink sink) 
	{
		synchronized(joined){
			
			ObjectMap<Object,Object> data=new ObjectMap<Object,Object>();
		
			data.put("feed", resourceSink.getStream().getPublishedName());	
			
			//Resource stores list of nodes.
			List<IComserverNode>subscribers= resourceSink.getSubscribers();
		
			ArrayList<Object>ret=new ArrayList<Object>();
				
			for(int i=0;i<subscribers.size();i++)
			{
				//Create array of node data.
				ret.add( subscribers.get(i).getNodeData());
			}
			data.put("players", ret);
			data.put("joined", joined);
			data.put("parted", parted);
			
			// create FLV invocation.
			
			// the flv tags here are the same tags that the action script codecs create. 
			// they do not have the full wrapper that is applied by the transcoder object;
			Map<String,VideoData> vData=new HashMap<String,VideoData>();
			
			// lets assume that this map contains up to n number of channels, 
			// and represents all the next frames 
			// that fall within up to a 100 millisecond window
			// from each channel. The smaller the window the better I imagine, 
			// to insure even spray of data accross the set.
			
			Iterator<String> channelCueable = vData.keySet().iterator();
			
			while(channelCueable.hasNext()){
				//assume file name is channel
				String channel = channelCueable.next();
				//same structure as tag as3 video codec.
				VideoData event = vData.get(channel);

				Map<Object,Object> params=new HashMap<Object,Object>();
				//this event goes to a Transcoder. 
				//private function onTag(sde:StreamDataEvent):void
				//using the channel names, feed tags to separate netstreams.
				params.put(channel, event);
				
				Notify invoke = InvocationFactory.createNotifyEvent("videoData", params);
				resourceSink.getStream().dispatchEvent(invoke);
			}
			
			
					
			
			parted.clear();
			joined.clear();
		}
	}

	@Override
	public void onClientAdded(IComserverNode connection) {
		synchronized(joined){
			joined.add(connection.getNodeId());
		}
	}

	@Override
	public void onClientRemoved(IComserverNode connection) {
		synchronized(joined){
			parted.add(connection.getNodeId());
		}
		
	}

}
